#pragma once

#include "core/color.h"
#include "external/DirectXTex/DirectXTex.h"

#include <string>

namespace renderit
{
	namespace messiah
	{
		enum EResourceType : uint8
		{
			EResourceType_Animation,
			EResourceType_CollisionShape,
			EResourceType_Material,
			EResourceType_Mesh,
			EResourceType_Model,
			EResourceType_NavigateMap,
			EResourceType_ParticleSystem,
			EResourceType_PointCloud,
			EResourceType_SkinSkeleton,
			EResourceType_Terrain,
			EResourceType_Texture,
			EResourceType_VisibilityCube,
			EResourceType_End
		};
		
		EResourceType GResourceTypeFromString(const std::string& type_name);
		const std::string& GResourceTypeString(EResourceType);

		const std::string& GResourceDirFromType(EResourceType);
		const std::string& GResourceDirFromType(const std::string& type_name);
		
		// From Messiah
		enum ESamplerFilter : uint8
		{
			ESamplerFilter_None = 0,
			ESamplerFilter_Point = 1,
			ESamplerFilter_Linear = 2,
			ESamplerFilter_Anisotropic = 3,
			ESamplerFilter_Max,
			//
			ESamplerFilter_last
		};

		enum ESamplerAddress : uint8
		{
			ESamplerAddress_None = 0,
			ESamplerAddress_Wrap = 1,
			ESamplerAddress_Mirror = 2,
			ESamplerAddress_Clamp = 3,
			ESamplerAddress_FromTexture = 4,
			//
			ESamplerAddress_last
		};

		enum EPixelFormat : uint8
		{
			EPixelFormat_Unknown = 0,
			// On screen render targets.
			EPixelFormat_A32R32G32B32F,
			EPixelFormat_A16B16G16R16F,
			EPixelFormat_R8G8B8A8,
			EPixelFormat_B5G6R5,
			EPixelFormat_A8L8,
			EPixelFormat_G16R16,
			EPixelFormat_G16R16F,
			EPixelFormat_G32R32F,
			EPixelFormat_R32F,
			EPixelFormat_R16F,
			EPixelFormat_L8,
			EPixelFormat_L16,
			EPixelFormat_A8,
			EPixelFormat_FloatRGB,
			EPixelFormat_FloatRGBA,
			EPixelFormat_D24,
			EPixelFormat_D32,
			// Artist texture.
			// DXT
			EPixelFormat_BC1,	// DXT1
			EPixelFormat_BC2,	// DXT2/DXT3
			EPixelFormat_BC3,	// DXT4/DXT5
			EPixelFormat_BC4,
			EPixelFormat_BC5,
			EPixelFormat_BC6H_SF,
			EPixelFormat_BC6H_UF,
			EPixelFormat_BC7,
			// PVR
			EPixelFormat_PVRTC2_RGB,
			EPixelFormat_PVRTC2_RGBA,
			EPixelFormat_PVRTC4_RGB,
			EPixelFormat_PVRTC4_RGBA,
			// ETC
			EPixelFormat_ETC1,
			EPixelFormat_ETC2_RGB,
			EPixelFormat_ETC2_RGBA,
			// ATC
			EPixelFormat_ATC_RGB,
			EPixelFormat_ATC_RGBA_E,
			EPixelFormat_ATC_RGBA_I,
			// ASTC
			EPixelFormat_ASTC_4x4_LDR,
			EPixelFormat_ASTC_5x4_LDR,
			EPixelFormat_ASTC_5x5_LDR,
			EPixelFormat_ASTC_6x5_LDR,
			EPixelFormat_ASTC_6x6_LDR,
			EPixelFormat_ASTC_8x5_LDR,
			EPixelFormat_ASTC_8x6_LDR,
			EPixelFormat_ASTC_8x8_LDR,
			EPixelFormat_ASTC_10x5_LDR,
			EPixelFormat_ASTC_10x6_LDR,
			EPixelFormat_ASTC_10x8_LDR,
			EPixelFormat_ASTC_10x10_LDR,
			EPixelFormat_ASTC_12x10_LDR,
			EPixelFormat_ASTC_12x12_LDR,
			// Hardware depth buffers.
			EPixelFormat_DepthStencil,
			EPixelFormat_ShadowDepth,
			// Extra pixel formats.
			EPixelFormat_R10G10B10A2,
			// End tag.
			EPixelFormat_last,
		};

		static const DXGI_FORMAT DXGI_format[EPixelFormat_last] =
		{
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_Unknown = 0,
			DXGI_FORMAT_R32G32B32A32_FLOAT,								//EPixelFormat_A32R32G32B32F,
			DXGI_FORMAT_R16G16B16A16_UNORM,								//EPixelFormat_A16R16G16B16,
			DXGI_FORMAT_B8G8R8A8_UNORM,									//EPixelFormat_R8G8B8A8,
			DXGI_FORMAT_B5G6R5_UNORM,									//EPixelFormat_B5G6R5,
			DXGI_FORMAT_R8G8_UNORM,										//EPixelFormat_A8L8,
			DXGI_FORMAT_R16G16_UNORM,									//EPixelFormat_G16R16,
			DXGI_FORMAT_R16G16_FLOAT,									//EPixelFormat_G16R16F,
			DXGI_FORMAT_R32G32_FLOAT,									//EPixelFormat_G32R32F,
			DXGI_FORMAT_R32_FLOAT,										//EPixelFormat_R32F,
			DXGI_FORMAT_R16_FLOAT,										//EPixelFormat_R16F,
			DXGI_FORMAT_R8_UNORM,										//EPixelFormat_L8,
			DXGI_FORMAT_R16_UNORM,										//EPixelFormat_L16,
			DXGI_FORMAT_A8_UNORM,										//EPixelFormat_A8,
			DXGI_FORMAT_R11G11B10_FLOAT,								//EPixelFormat_FloatRGB,
			DXGI_FORMAT_R16G16B16A16_FLOAT,								//EPixelFormat_FloatRGBA,
			DXGI_FORMAT_D32_FLOAT,										//EPixelFormat_D24,
			DXGI_FORMAT_D32_FLOAT,										//EPixelFormat_D32,
			DXGI_FORMAT_BC1_UNORM,										//EPixelFormat_BC1,	// DXT1
			DXGI_FORMAT_BC2_UNORM,										//EPixelFormat_BC2,	// DXT2/DXT3
			DXGI_FORMAT_BC3_UNORM,										//EPixelFormat_BC3,	// DXT4/DXT5
			DXGI_FORMAT_BC4_UNORM,										//EPixelFormat_BC4,
			DXGI_FORMAT_BC5_UNORM,										//EPixelFormat_BC5,
			DXGI_FORMAT_BC6H_SF16,										//EPixelFormat_BC6H_SF,
			DXGI_FORMAT_BC6H_UF16,										//EPixelFormat_BC6H_UF,
			DXGI_FORMAT_BC7_UNORM,										//EPixelFormat_BC7,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_PVRTC2_RGB,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_PVRTC2_RGBA,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_PVRTC4_RGB,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_PVRTC4_RGBA,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ETC1,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ETC2_RGB,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ETC2_RGBA,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ATC_RGB,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ATC_RGBA_E,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ATC_RGBA_I,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_4x4_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_5x4_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_5x5_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_6x5_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_6x6_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_8x5_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_8x6_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_8x8_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_10x5_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_10x6_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_10x8_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_10x10_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_12x10_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ASTC_12x12_LDR,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_DepthStencil,
			DXGI_FORMAT_UNKNOWN,										//EPixelFormat_ShadowDepth,
		};

		enum ETextureCompression : uint8
		{
			ETextureCompression_Default = 0,
			ETextureCompression_NormalMap = 1,
			ETextureCompression_DisplacementMap = 2,
			ETextureCompression_Grayscale = 3,
			ETextureCompression_HDR = 4,
			ETextureCompression_NormalMapUncompress = 5,
			ETextureCompression_NormalMapBC5 = 6,
			ETextureCompression_VectorMap = 7,
			ETextureCompression_Uncompressed = 8,
			ETextureCompression_LightMap = 9,
			ETextureCompression_EnvMap = 10,
			ETextureCompression_MixMap = 11,
			ETextureCompression_UI = 12,
			ETextureCompression_TerrainBlock = 13,
			ETextureCompression_TerrainIndex = 14,
		};

		enum ETextureLODGroup : uint8
		{
			ETextureLODGroup_World = 0,
			ETextureLODGroup_WorldNormalMap = 1,
			ETextureLODGroup_WorldSpecular = 2,
			ETextureLODGroup_Character = 3,
			ETextureLODGroup_CharacterNormalMap = 4,
			ETextureLODGroup_CharacterSpecular = 5,
			ETextureLODGroup_Weapon = 6,
			ETextureLODGroup_WeaponNormalMap = 7,
			ETextureLODGroup_WeaponSpecular = 8,
			ETextureLODGroup_Cinematic = 9,
			ETextureLODGroup_Effect = 10,
			ETextureLODGroup_EffectUnfiltered = 11,
			ETextureLODGroup_Sky = 12,
			ETextureLODGroup_UI = 13,
			ETextureLODGroup_RenderTarget = 14,
			ETextureLODGroup_ShadowMap = 15,
			ETextureLODGroup_LUT = 16,
			ETextureLODGroup_TerrainBlockMap = 17,
			ETextureLODGroup_TerrainIndexMap = 18,
			ETextureLODGroup_TerrainLightMap = 19,
			ETextureLODGroup_ImageBaseReflection = 20,
		};

		enum ETextureMipGen : uint8
		{
			ETextureMipGen_FromTextureGroup = 0,
			ETextureMipGen_Simple = 1,
			ETextureMipGen_Sharpen = 2,
			ETextureMipGen_NoMip = 3,
			ETextureMipGen_Blur = 4,
		};

		struct Texture2DInfo
		{
			ESamplerFilter			MagFilter;
			/*1*/
			ESamplerFilter			MinFilter;
			/*2*/
			ESamplerFilter			MipFilter;
			/*3*/
			ESamplerAddress			AddressU;
			/*4*/
			ESamplerAddress			AddressV;
			/*5*/
			EPixelFormat			Format;
			/*6*/
			uint8					MipLevel;
			/*7*/
			bool					IsSRGB : 1;

			bool					IsDynamicRange : 1;

			bool					NoneCompression : 1;

			bool					CompressionNoAlpha : 1;
			uint8					_padding_ : 4;
			/*8*/
			ETextureCompression		CompressionPreset;
			/*9*/
			ETextureLODGroup		LODGroup;
			/*10*/
			ETextureMipGen			MipGenPreset;
			/*11*/
			uint8					_padding2_;
			/*12*/
			uint16					Width;
			/*14*/
			uint16					Height;
			/*16*/
			core::color4f			DefaultColor;
			/*20*/

			//! \ctor
			Texture2DInfo()
				: MagFilter(ESamplerFilter_Linear)
				, MinFilter(ESamplerFilter_Linear)
				, MipFilter(ESamplerFilter_Linear)
				, AddressU(ESamplerAddress_Wrap)
				, AddressV(ESamplerAddress_Wrap)
				, Format(EPixelFormat_Unknown)
				, MipLevel(0)
				, IsSRGB(false)
				, IsDynamicRange(false)
				, NoneCompression(false)
				, CompressionNoAlpha(false)
				, _padding_(0)
				, CompressionPreset(ETextureCompression_Default)
				, LODGroup(ETextureLODGroup_World)
				, MipGenPreset(ETextureMipGen_FromTextureGroup)
				, _padding2_(0)
				, Width(0)
				, Height(0)
				, DefaultColor(0, 0, 0, 0)
			{
			}
		};

		enum ETexConvertQuality
		{
			ETexConvertQuality_Fastest = 0,
			ETexConvertQuality_Normal = 1,
			ETexConvertQuality_Production = 2,
			ETexConvertQuality_Highest = 3,
		};

		// Texture convert options.
		struct TextureCompressOption
		{
			uint32					MipLevels;		// Generate mip levels.
			uint32					ResizeWidth;	// Resize destination width.
			uint32					ResizeHeight;	// Resize destination height.
			uint32					DownSampleScale;	// Down sample scale for source.
			EPixelFormat			Format;			// Format to generate.
			ETexConvertQuality		Quality;		// Convert quality.
			ETextureCompression		Compression;	// Compression option.
			ETextureMipGen			MipGen;			// Mip gen option.
			int						SRGBIn;			// Input as SRGB color.
			int						SRGBOut;		// Output as SRGB color.
			int						Premultiply;	// Premultiply color.
			int						SeparateAlpha;	// Separate alpha blend.

			uint32					MaxTextureSize;		// max texture size
			float					NormalSmoothRate;	// out.rg = in.rg*(1-mipLevel*NormalSmoothRate);
			float					MixRoughenRate;		// out.r = in.r*pow(MixRoughenRate,mipLevel);
			bool					SmoothNormalMap;	// smooth normal map's mipmap
			bool					RoughenMixMap;		// roughen mix map's mipmap
			bool					KeepRaw;			// Keep .pvr .dds .etc file

														//! \ctor
			FORCEINLINE TextureCompressOption()
				: MipLevels(0)
				, ResizeWidth(0)
				, ResizeHeight(0)
				, DownSampleScale(0)
				, Format(EPixelFormat_Unknown)
				, Quality(ETexConvertQuality_Highest)
				, Compression(ETextureCompression_Default)
				, SRGBIn(1)
				, SRGBOut(1)
				, Premultiply(0)
				, SeparateAlpha(1)
				, MaxTextureSize(8192)
				, NormalSmoothRate(0.05f)
				, MixRoughenRate(0.95f)
				, SmoothNormalMap(false)
				, RoughenMixMap(false)
				, KeepRaw(false)
			{
			}
		};

		enum ETextureType : uint8
		{
			//! \display	Texture-1D
			ETextureType_1D = 0,
			//! \display	Texture-2D
			ETextureType_2D,
			//! \display	Texture-3D
			ETextureType_3D,
			//! \display	Texture-Cube
			ETextureType_Cube,
			//
			ETextureType_last
		};

		struct RsTextureInfo
		{
			uint32			Size;				// [ 0- 4]	Data size.
												// Texture data.
			ETextureType	Type : 8;			// [ 4- 5]	Texture type.
			EPixelFormat	Format : 8;			// [ 5- 6]	Texture format.
			uint8			MipLevel : 8;		// [ 6- 7]	Texture mip level count.
			uint8			Flags : 8;			// [ 7- 8]	Texture flags.
		};

		struct RsTextureSliceInfo
		{
			uint32			Size;				// [ 0- 4]	Data size.
												// Texture data.
			uint16			Width;				// [ 4- 6]	Texture width.
			uint16			Height;				// [ 6- 8]	Texture height.
			uint16			Depth;				// [ 8-10]	Texture depth.
			uint16			PitchInByte;		// [11-12]	Texture pitch in byte.
			uint32			SliceInByte;		// [12-14]	Slice pitch in byte.
		};
	}
}